#pragma once
#ifndef _LISTQUEUE_H
#define _LISTQUEUE_H

template <typename T> class ListQueue;

template <typename T>
class Node {

template <typename T> 
friend class ListQueue;

private:
	T val;
	Node* next;
	Node(const T& in) :val(in) {
		next = NULL;
	}
	Node() {
		next = NULL;
	}
};

template <typename T>
class ListQueue {

private:
	Node<T>* begin;
	Node<T>* end;

public:
	ListQueue();
	~ListQueue();
	bool empty();
	void push(const T& in);
	void pop();
	const T& front();
	const T& back();
};

template <typename T>
ListQueue<T>::ListQueue() {
	Node<T>* init_node = new Node<T>();
	begin = init_node;
	end = init_node;
}

template <typename T>
ListQueue<T>::~ListQueue() {
	while (!empty()){
		pop();
	}
	delete begin;
}

template <typename T>
bool ListQueue<T>::empty() {
	return begin == end;
}

template <typename T>
void ListQueue<T>::push(const T& in) {
	Node<T>* newnode = new Node<T>(in);
	end->next = newnode;
	end = newnode;
}

template <typename T>
void ListQueue<T>::pop() {
	if (empty()) {
		throw "The queue is empty.Can not pop.";
	}
	Node<T>* tmp = begin->next;
	if (begin->next == end) {
		delete end;
		end = begin;
	} else {
		begin->next = tmp->next;
		delete tmp;
	}
}

template <typename T>
const T& ListQueue<T>::front() {
	if (empty()) {
		throw "The queue is empty! No front element.";
	}
	return begin->next->val;
}

template <typename T>
const T& ListQueue<T>::back() {
	if (empty()) {
		throw "The queue is empty! No front element.";
	}
	return end->val;
}

#endif